import os
import re
import sqlite3
from pydub import AudioSegment
import logging
from logging.handlers import RotatingFileHandler

# 设置日志记录，将日志文件放在 ./output 目录下
log_dir = './output'
if not os.path.exists(log_dir):
    os.makedirs(log_dir)
log_file = os.path.join(log_dir, 'merge_audioC.log')

# 设置日志级别为 INFO，以确保所有日志都被记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# 配置日志处理器，确保日志写入文件
handler = RotatingFileHandler(log_file, maxBytes=10000, backupCount=1, encoding='utf-8')
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)

def sanitize_filename(filename):
    """清理文件名，使其适应文件系统要求。"""
    return re.sub(r'[\\/*?:"<>|]', "_", filename).strip("_")

def convert_milliseconds_to_lrc_time(ms):
    """将毫秒转换为LRC格式的时间戳 [hh:mm:ss.xx]"""
    seconds = ms // 1000
    minutes = seconds // 60
    hours = minutes // 60
    minutes = minutes % 60
    seconds = seconds % 60
    milliseconds = ms % 1000

    if hours > 0:
        return f"{hours:02}:{minutes:02}:{seconds:02}.{milliseconds//10:02}"
    else:
        return f"{minutes:02}:{seconds:02}.{milliseconds//10:02}"

def generate_lrc_file(output_filename, text_list):
    """生成对应的 .lrc 文件，包含时间戳"""
    lrc_filename = os.path.normpath(output_filename)  # 确保路径格式统一
    try:
        logger.info(f"尝试生成 LRC 文件: {lrc_filename}")
        
        # 检查并创建目录
        os.makedirs(os.path.dirname(lrc_filename), exist_ok=True)

        current_time = 0
        with open(lrc_filename, 'w', encoding='utf-8') as lrc_file:
            for duration, sentence in text_list:
                timestamp = convert_milliseconds_to_lrc_time(current_time)
                lrc_file.write(f"[{timestamp}]{sentence}\n")
                current_time += duration  # 累加当前句子的时长
                logger.info(f"时间戳: {timestamp}, 写入句子: {sentence}")
                
        logger.info(f"LRC 文件生成成功: {lrc_filename}")
    except Exception as e:
        logger.error(f"生成 LRC 文件时出错: {str(e)}")

def generate_merged_filename(base_filename, part=None, ext="ogg"):
    """根据部分生成合并后的文件名。"""
    try:
        merged_filename = f'{base_filename}'
        if part:
            merged_filename = f'{merged_filename}_part{part}.{ext}'
        else:
            merged_filename = f'{merged_filename}.{ext}'

        merged_filename = os.path.normpath(os.path.join('./output', merged_filename))
        logger.info(f"生成文件名: {merged_filename}")
        return merged_filename
    except Exception as e:
        logger.error(f"生成文件名时出错: {e}")
        return os.path.normpath(os.path.join('./output', f'default_output.{ext}'))

def trigger_merge_logic(db_path='./db/data.db'):
    """基于数据库中的信息触发合并过程，并详细记录合并过程。"""
    try:
        conn = sqlite3.connect(db_path)
        cursor = conn.cursor()

        # 从submission_info表获取文件名前缀信息
        base_filename = get_filename_prefix_from_submission_info(db_path)

        # 获取所有已处理的音频文件信息
        cursor.execute('''SELECT audio_filename, audio_duration, sentence, original_order 
                          FROM split_sentences WHERE status="completed" ORDER BY original_order''')
        rows = cursor.fetchall()
        conn.close()

        if not rows:
            logger.error("没有从数据库中找到任何记录。")
            return []

        total_duration = sum(row[1] for row in rows)  # 计算总时长

        # 判断总时长，选择分割策略
        if total_duration >= 2 * 60 * 60 * 1000:  # 大于等于2小时
            logger.info(f"总时长超过2小时，采用近似40分钟分割法。")
            segment_durations = 40 * 60 * 1000  # 40分钟
            split_points = calculate_nearest_segments(rows, segment_durations)
        elif 55 * 60 * 1000 <= total_duration < 2 * 60 * 60 * 1000:  # 介于55分钟和2小时之间
            logger.info(f"总时长介于55分钟到2小时之间，采用三等分法。")
            segment_durations = total_duration / 3  # 近似三等分
            split_points = calculate_nearest_segments(rows, segment_durations)
        else:
            logger.info(f"总时长低于55分钟，跳转到 D 逻辑。")
            os.system("python merge_audioD.py")
            return

        if split_points:
            # 根据分割点合并音频文件并生成 LRC
            merged_filenames = []
            for i, (start, end) in enumerate(split_points):
                segment_rows = rows[start:end + 1]
                audio_files = [os.path.normpath(os.path.join('./temp', row[0])) for row in segment_rows]
                text_list = [(row[1], row[2]) for row in segment_rows]
                merged_filename = generate_merged_filename(base_filename, part=i + 1)
                merge_files(audio_files, merged_filename)
                generate_lrc_file(merged_filename.replace('.ogg', '.lrc'), text_list)
                merged_filenames.append(merged_filename)
                logger.info(f"生成了部分: {merged_filename}")

            logger.info(f"所有部分生成完成: {merged_filenames}")
        else:
            logger.info("没有生成部分文件。")

    except Exception as e:
        logger.error(f"触发合并逻辑时出错: {e}")
        return []

def calculate_nearest_segments(rows, segment_duration):
    """计算近似分割点，返回原始order的分割点。"""
    segments = []
    start = 0
    current_duration = 0
    for i, row in enumerate(rows):
        current_duration += row[1]
        if current_duration >= segment_duration:
            segments.append((start, i))
            start = i + 1
            current_duration = 0

    # 处理最后的部分
    if start < len(rows):
        segments.append((start, len(rows) - 1))

    return segments

def merge_files(audio_files, output_filename):
    """将多个音频文件合并为一个，并记录合并过程。"""
    output_filename = os.path.normpath(output_filename)  # 确保路径格式统一
    logger.info(f"开始合并文件: {audio_files} 到 {output_filename}")
    try:
        # 这里初始化音频合并所需的变量，确保没有遗留的状态
        merged_audio = AudioSegment.empty()
        
        for file in audio_files:
            file = os.path.normpath(file)  # 确保路径格式统一
            logger.info(f"正在处理文件: {file}")
            audio_segment = AudioSegment.from_file(file)
            logger.info(f"音频时长: {len(audio_segment)} 毫秒")
            merged_audio += audio_segment
        
        # 导出音频文件，检查是否成功
        merged_audio.export(output_filename, format="ogg")
        logger.info(f"文件合并成功: {output_filename}")
        return output_filename
    except Exception as e:
        logger.error(f"音频合并失败: {e}")
        return None

def get_filename_prefix_from_submission_info(db_path):
    """从submission_info表获取文件名前缀信息"""
    try:
        conn = sqlite3.connect(db_path)
        cursor = conn.cursor()
        cursor.execute('''SELECT filename, first_slice FROM submission_info LIMIT 1''')
        result = cursor.fetchone()
        conn.close()

        if result:
            filename, first_slice = result

            if filename:
                prefix = sanitize_filename(filename)
            elif first_slice:
                first_slice = sanitize_filename(first_slice)
                # 检查是否包含中文
                if re.search(r'[\u4e00-\u9fff]', first_slice):
                    # 截取前10个字符（只保留中文开头的前10个字符）
                    prefix = first_slice[:10]
                else:
                    prefix = first_slice
            else:
                prefix = "【聆听】"
        else:
            prefix = "【聆听】"

        logger.info(f"获取文件名前缀成功: {prefix}")
        return prefix
    except Exception as e:
        logger.error(f"获取文件名前缀信息时出错: {e}")
        return "【聆听】"

if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser(description="从数据库中生成 .lrc 文件并合并音频文件。")
    parser.add_argument("--db_path", type=str, default='./db/data.db', help="SQLite 数据库的路径。")
    args = parser.parse_args()

    try:
        trigger_merge_logic(args.db_path)
        print("所有文件生成完成")
    except Exception as e:
        logger.error(f"程序运行时出错: {e}")
        print(f"程序运行时出错: {e}")

    # 防止程序自动退出，等待用户输入
    input("按回车键退出...")
